#!/usr/local/bin/perl -w
#////////////////////////////////////////////////////////////
#
# rmdom.pl	
#  remove mail/cal domain and its users
#   without the series of deletion/purge commands
#
#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#
# author: Marcin Wisnios <wisnios@gmail.com>
#
# This script is a part of Commandline Support Tools project
# http://code.google.com/p/cs-tools/
#
#////////////////////////////////////////////////////////////

use strict;
use warnings;

use Carp qw(carp croak);
use Term::ReadKey;
use Net::LDAP;
use Net::OpenSSH;
use Switch;

my $LDHOST = 'ldap.localdomain';
my $LDPORT = '389';
my $BASE   = 'o=isp';
my $FEHOST = 'frontend.localdomain';
my $BEHOST = 'backend.localdomain';
my $DN;
my $PWFILE;
my $PW;
my $DOMAIN;
my $YES;

my $CSCLEAN = '/opt/sun/comms/calendar/SUNWics5/cal/sbin/csclean';
my $MSUSERPURGE = '/opt/sun/comms/messaging64/lib/msuserpurge';
my $COMMADMIN = '/opt/sun/comms/da/bin/commadmin';
my $ADMINPASS = '`/opt/sun/comms/messaging64/bin/configutil -o local.service.proxy.adminpass`';

my $query;
my @values;
my $result;
my $dn;
my $maildom;
my $caldom;
my $answer;

my %delInetMail    = (
		       inetUserStatus => 'deleted',
		       mailUserStatus => 'deleted',
		     );

my %delInetMailCal = (
		       inetUserStatus => 'deleted',
		       mailUserStatus => 'deleted',
		       icsStatus => 'deleted'
		     );

my %delInetGroup   = (
		       inetMailGroupStatus => 'deleted'
		     );

my %actInetMail    = (
		       inetUserStatus => 'active',
		       mailUserStatus => 'active',
		     );

my %actInetMailCal = (
		       inetUserStatus => 'active',
		       mailUserStatus => 'active',
		       icsStatus => 'active'
		     );

my %actInetGroup   = (
		       inetMailGroupStatus => 'active'
		     );


while (my $arg = shift @ARGV) {
	switch ($arg) {
	  case('-lh') { $LDHOST = shift @ARGV; }
	  case('-lp') { $LDPORT = shift @ARGV; }
	  case('-ld') { $DN = shift @ARGV; }
	  case('-lb') { $BASE = shift @ARGV; }
	  case('-lf') { $PWFILE = shift @ARGV; }
	  case('-fe') { $FEHOST = shift @ARGV; }
	  case('-be') { $BEHOST = shift @ARGV; }
	  case('-dn') { $DOMAIN = shift @ARGV; }
	  case('-yes') { $YES = 1; }
	  case('-h') {
		print "usage: $0 [options]\n";
		print "options:\n";

		print "\t-lh host\tLDAP server name or IP address";
		$LDHOST && print " (default: $LDHOST)";
		print "\n";

		print "\t-lp port\tLDAP server TCP port number";
		$LDPORT && print " (default: $LDPORT)";
		print "\n";

		print "\t-lb basedn\tbase dn";
		$BASE && print " (default: $BASE)";
		print "\n";

		print "\t-ld binddn\tbind dn";
		$DN && print " (default: $DN)";
		print "\n";

		print "\t-lf file\tread bind passwd";
		$PWFILE && print " (default: $PWFILE)";
		print "\n";

		print "\t-fe host\tFrontEnd server name or IP address";
		$FEHOST && print " (default: $FEHOST)";
		print "\n";

		print "\t-be host\tBackEnd server name or IP address";
		$BEHOST && print " (default: $BEHOST)";
		print "\n";

		print "\t-yes\t\tdo not prompt for confirmation\n";
		print "\t-h\t\tdisplay usage information\n";
		exit;
	  }
	}
}


my $ldap = Net::LDAP->new($LDHOST, port => $LDPORT) or croak $@;

my $fessh = Net::OpenSSH->new($FEHOST, timeout => 5);
$fessh->error && croak "fe: " . $fessh->error;
my $bessh = Net::OpenSSH->new($BEHOST, timeout => 5);
$bessh->error && croak "be: " . $bessh->error;


print "fe  : $FEHOST\n";
print "be  : $BEHOST\n";

my $ldapline ="ldap: $LDHOST:$LDPORT\n";
print $ldapline;

for (2..length($ldapline)) {
	print '%';
}
print "\n";

if ($DN) {
	print "bind dn: $DN\n";
}
else {
	print "bind dn: ";
	$DN = <>;
	chomp($DN);
}

if ($PWFILE) {
	open(my $PWF, '<', $PWFILE) or croak("$PWFILE: $!");

	$PW = <$PWF>;
	chomp($PW);
	print "bind pw: (hidden)\n";

	close($PWF);
}
else {
	print "bind passwd: ";
	ReadMode('noecho');
	$PW= <>;
	ReadMode('restore');
	chomp($PW);

	print "\n";
}

my $mesg = $ldap->bind($DN, password => $PW) or croak $@;
if ($mesg->code) {
	print $mesg->error,"\n";
	exit;
}

if ($BASE) {
	print "base dn: $BASE\n";
}
else {
	print "base dn: ";
	$BASE = <>;
	chomp($BASE);
}

if ($DOMAIN) {
	print "domain: $DOMAIN\n";
}
else {
	print "domain: ";
	$DOMAIN = <>;
	chomp($DOMAIN);
}


$query = $ldap->search(base => "$BASE", filter => "(o=$DOMAIN)");
foreach ($query->entries) {
	@values = $_->get_value('objectClass', asref => 1);
	foreach my $row (@values) {
		"@$row" =~ /maildomain/ and $maildom = 1;
		"@$row" =~ /icscalendardomain/ and $caldom = 1;
	}
}

$maildom && print "mail domain ok\n";
$caldom && print "cal domain ok\n";

$query = $ldap->search(base => "o=$DOMAIN,$BASE", filter => "(&(uid=*)(inetUserStatus=active))");
$query->count && print "active users: " . $query->count . "\n";

foreach ($query->entries) {
	my $dn = $_->dn();
	if ($maildom && $caldom) {
	    	$result = $ldap->modify($dn, changes => [ replace => [ %delInetMailCal ] ]);
	}
	elsif ($maildom) {
	    	$result = $ldap->modify($dn, changes => [ replace => [ %delInetMail ] ]);
	}
	$result->code && carp "failed to modify user entry: " . $result->error;
}

$query = $ldap->search(base => "o=$DOMAIN,$BASE", filter => "(inetMailGroupStatus=active)");
$query->count && print "active groups: " . $query->count . "\n";

foreach ($query->entries) {
	my $dn = $_->dn();
	$result = $ldap->modify($dn, changes => [ replace => [ %delInetGroup ] ]);
	$result->code && carp "failed to modify group entry: " . $result->error;
}


if ($YES) {
	print "executor has shown no fear\n";
	$answer = 'yes';
}
else {
	print "are you sure (yes to confirm)? ";
	$answer = <>;
	chomp($answer);
}


if ($answer eq "yes") {
	$caldom and my($besshout, $bessherr) = $bessh->capture2("$CSCLEAN -g 0 clean $DOMAIN");

	($besshout, $bessherr) = $bessh->capture2("$MSUSERPURGE -d $DOMAIN -g 0");

	my($fesshout, $fessherr) = $fessh->capture2("$COMMADMIN domain delete -D admin -w $ADMINPASS -d $DOMAIN");
	if (substr($fesshout,0,2) eq "OK") {
		print "domain deleted\n";
	}

	($fesshout, $fessherr) = $fessh->capture2("$COMMADMIN domain purge -D admin -w $ADMINPASS -d $DOMAIN -g 0");
	if (substr($fesshout,0,2) eq "OK") {
		print "domain purged\n";
	}
	else {
		print "domain NOT purged\n\n";
		print "purge could not be performed until:\n";
		print "  inetUserStatus: deleted\n";
		print "  mailUserStatus: removed\n";
		print "  icsStatus: removed\n";
		print "  inetMailGroupStatus: deleted\n";
		print "check above attributes manually\n";
	}
}
else {
	$query = $ldap->search(base   => "o=$DOMAIN,$BASE", filter => "(&(uid=*)(inetUserStatus=deleted))");
	foreach ($query->entries) {
		$dn = $_->dn();

		if ($maildom && $caldom) {
			$result = $ldap->modify($dn, changes => [ replace => [ %actInetMailCal ] ]);
		}
		elsif ($maildom) {
			$result = $ldap->modify($dn, changes => [ replace => [ %actInetMail ] ]);
		}

		$result->code && carp "failed to modify user entry: " . $result->error;
	}
	$query->count && print "users' status has been changed back to active\n";

	$query = $ldap->search(base => "o=$DOMAIN,$BASE", filter => "(inetMailGroupStatus=deleted)");
	foreach ($query->entries) {
		my $dn = $_->dn();
		$result = $ldap->modify($dn, changes => [ replace => [ %actInetGroup ] ]);
		$result->code && carp "failed to modify group entry: " . $result->error;
	}
	$query->count && print "groups' status has been changed back to active\n";
}


$ldap->unbind;
